// Created by lostleaf on 2020/5/23.
// vn.py 宽睿 OES 箭鱼快速订单系统 python 封装代码实现

#include "vnoestd.h"
int32 vnTdMsgHandler(OesApiSessionInfoT *pSessionInfo, SMsgHeadT *pMsgHead,
                     void *pMsgBody, void *pCallbackParams) {
  auto *p_td = static_cast<TdApi *>(pCallbackParams);
  auto *pRspMsg = static_cast<OesRspMsgBodyT *>(pMsgBody);

  TdTask task;

  if (pSessionInfo) {
    task.pSessionInfo = new OesApiSessionInfoT;
    *task.pSessionInfo = *pSessionInfo;
  }

  if (pMsgHead) {
    task.pMsgHead = new SMsgHeadT;
    *task.pMsgHead = *pMsgHead;
  }

  if (pRspMsg) {
    task.pMsgBody = new OesRspMsgBodyT;
    *task.pMsgBody = *pRspMsg;
  }

  p_td->task_queue.push(task);
  return 0;
}

bool TdApi::init(const std::string &config_path) {
  if (active) {
    SLOG_ERROR("已在运行, 不能重复初始化!", active);
    return false;
  }

  if (!OesApi_ParseAllConfig(config_path.c_str(), &api_cfg)) {
    SLOG_ERROR("解析配置文件失败! cfgFile[%s]", config_path.c_str());
    return false;
  }

  /* 创建异步API的运行时环境 (初始化日志, 创建上下文环境) */
  OesAsyncApiContextT *pAsyncContext =
      OesAsyncApi_CreateContext(config_path.c_str());
  if (!pAsyncContext) {
    SLOG_ERROR("创建异步API的运行时环境失败!");
    return false;
  }

  /* 添加初始的委托通道 */
  OesAsyncApiChannelT *pOrdChannel = nullptr;
  if (api_cfg.ordChannelCfg.addrCnt > 0) {
    pOrdChannel = OesAsyncApi_AddChannel(
        pAsyncContext, OESAPI_CHANNEL_TYPE_ORDER,
        OESAPI_CFG_DEFAULT_KEY_ORD_ADDR, &api_cfg.ordChannelCfg, nullptr,
        vnTdMsgHandler, this, nullptr, nullptr, nullptr, nullptr);
    if (!pOrdChannel) {
      SLOG_ERROR("添加委托通道失败! channelTag[%s]",
                 OESAPI_CFG_DEFAULT_KEY_ORD_ADDR);
      OesAsyncApi_ReleaseContext(pAsyncContext);
      return false;
    }
  }

  /* 添加初始的回报通道 */
  OesAsyncApiChannelT *pRptChannel = nullptr;
  if (api_cfg.rptChannelCfg.addrCnt > 0) {
    pRptChannel = OesAsyncApi_AddChannel(
        pAsyncContext, OESAPI_CHANNEL_TYPE_REPORT,
        OESAPI_CFG_DEFAULT_KEY_RPT_ADDR, &api_cfg.rptChannelCfg,
        &api_cfg.subscribeInfo, vnTdMsgHandler, this, nullptr, nullptr, nullptr,
        nullptr);
    if (!pRptChannel) {
      SLOG_ERROR("添加回报通道失败! channelTag[%s]",
                 OESAPI_CFG_DEFAULT_KEY_RPT_ADDR);
      OesAsyncApi_ReleaseContext(pAsyncContext);
      return false;
    }
  }

  if (OesAsyncApi_GetChannelCount(pAsyncContext) <= 0 &&
      api_cfg.qryChannelCfg.addrCnt <= 0) {
    SLOG_ERROR("尚未配置任何有效的委托/回报/查询通道, 无法启动! "
               "请检查配置信息是否正确!");
    return false;
  }

  /* 连接查询通道 */
  if (api_cfg.qryChannelCfg.addrCnt > 0) {
    p_qry_channel = new OesApiSessionInfoT{NULLOBJ_OESAPI_SESSION_INFO};
    if (!OesApi_InitQryChannel2(p_qry_channel, &api_cfg.qryChannelCfg)) {
      SLOG_ERROR("连接查询通道失败! error[%d - %s]", OesApi_GetLastError(),
                 OesApi_GetErrorMsg(OesApi_GetLastError()));
      delete p_qry_channel;
      return false;
    }
    active = true;
  } else {
    SLOG_INFO("未配置查询通道, 将忽略查询通道并继续执行!");
  }

  /* 启动异步API线程 (连接委托通道和回报通道) */
  if (OesAsyncApi_GetChannelCount(pAsyncContext) > 0) {
    OesAsyncApi_SetPreconnectAble(pAsyncContext, TRUE);

    if (!OesAsyncApi_Start(pAsyncContext)) {
      SLOG_ERROR("启动异步API线程失败! error[%d - %s]", OesApi_GetLastError(),
                 OesApi_GetErrorMsg(OesApi_GetLastError()));
      stop();
      return false;
    }
  } else {
    SLOG_INFO("未配置委托通道或回报通道, 无需启动异步API线程!");
  }

  SLOG_INFO("启动交易接口实例");

  active = true;
  task_thread = std::thread(&TdApi::processTask, this);
  p_context = pAsyncContext;
  p_ord_channel = pOrdChannel;
  p_rpt_channel = pRptChannel;

  return true;
}

void TdApi::stop() {
  if (active) {
    SLOG_INFO("停止交易接口实例并释放相关资源...");
  }

  /* 停止并销毁异步API线程 */
  if (p_context) {
    OesAsyncApi_Stop(p_context);
    OesAsyncApi_ReleaseContext(p_context);
    p_context = nullptr;
  }

  /* 关闭并销毁查询通道 */
  if (p_qry_channel) {
    OesApi_Destory(p_qry_channel);
    p_qry_channel = nullptr;
  }

  // 关闭任务队列和工作线程
  task_queue.terminate();
  task_thread.join();

  active = false;
}

int32 TdApi::sendBatchOrdersReq(const py::list &reqs) {
  std::vector<OesOrdReqT> v;
  v.reserve(reqs.size());
  for (auto obj : reqs) {
    auto reqdict = obj.cast<py::dict>();
    v.push_back(OesOrdReqT{NULLOBJ_OES_ORD_REQ});

    getValue<int32>(reqdict, "clSeqNo", v.back().clSeqNo);
    getValue<uint8>(reqdict, "mktId", v.back().mktId);
    getValue<uint8>(reqdict, "ordType", v.back().ordType);
    getValue<uint8>(reqdict, "bsType", v.back().bsType);
    getArray<char>(reqdict, "invAcctId", v.back().invAcctId, 16);
    getArray<char>(reqdict, "securityId", v.back().securityId, 16);
    getValue<int32>(reqdict, "ordQty", v.back().ordQty);
    getValue<int32>(reqdict, "ordPrice", v.back().ordPrice);
    getValue<int64>(reqdict, "origClOrdId", v.back().origClOrdId);
    if (reqdict.contains("userInfo")) {
      auto reqdict_userInfo = reqdict["userInfo"].cast<py::dict>();
      getValue<uint64>(reqdict_userInfo, "u64", v.back().userInfo.u64);
      getValue<int64>(reqdict_userInfo, "i64", v.back().userInfo.i64);
      getArray<uint32>(reqdict_userInfo, "u32", v.back().userInfo.u32, 2);
      getArray<int32>(reqdict_userInfo, "i32", v.back().userInfo.i32, 2);
      getArray<char>(reqdict_userInfo, "c8", v.back().userInfo.c8, 8);
    }
  }
  int32 ret =
      OesAsyncApi_SendBatchOrdersReq2(p_ord_channel, v.data(), v.size());
  return ret;
}

void TdApi::processTask() {
  try {
    while (this->active) {
      TdTask task = this->task_queue.pop();
      // std::cout << "msg id " << static_cast<int>(task.pMsgHead->msgId) << std::endl;
      delete task.pMsgBody;
      delete task.pSessionInfo;
      delete task.pMsgHead;
    }
  } catch (const TerminatedError &) {
  }
}

// 自动生成的函数封装
#include "vnoestd_function_source.cpp"

// 自动生成的pybind11绑定代码
#include "vnoestd_bind_source.cpp"
